/*
 * Vec4.cpp.inl
 *
 *  Created on: 19.09.2009
 *      Author: christoph
 */

// this file is included by its header file to satisfy the compiler

template <typename Real>
Vec4<Real>::Vec4() {
	data[0] = 0;
	data[1] = 0;
	data[2] = 0;
	data[3] = 0;
}

template <typename Real>
Vec4<Real>::Vec4( const Vec3<Real>& v3V, const Real rW ) {
	data[0] = v3V.x();
	data[1] = v3V.y();
	data[2] = v3V.z();
	data[3] = rW;
}

template < typename Real >
Vec4<Real>::Vec4( const Real rX, const Real rY, const Real rZ, const Real rW ) {
	data[0] = rX;
	data[1] = rY;
	data[2] = rZ;
	data[3] = rW;
}

template <typename Real>
Vec4<Real>::Vec4( const Vec4<Real>& v4V ) {
	data[0] = v4V.x();
	data[1] = v4V.y();
	data[2] = v4V.z();
	data[3] = v4V.w();
}

template <typename Real>
Vec4<Real>::~Vec4() {
}

template <typename Real>
Real Vec4<Real>::x() const {
	return data[0];
}

template <typename Real>
Real& Vec4<Real>::x() {
	return data[0];
}

template <typename Real>
Real Vec4<Real>::y() const {
	return data[1];
}

template <typename Real>
Real& Vec4<Real>::y() {
	return data[1];
}

template <typename Real>
Real Vec4<Real>::z() const {
	return data[2];
}

template <typename Real>
Real& Vec4<Real>::z() {
	return data[2];
}

template <typename Real>
Real Vec4<Real>::w() const {
	return data[3];
}

template <typename Real>
Real& Vec4<Real>::w() {
	return data[3];
}

template <typename Real>
const Real Vec4<Real>::operator [] ( int iIndex ) const {
	return data[iIndex];
}

template <typename Real>
Real& Vec4<Real>::operator [] ( int iIndex ) {
	return data[iIndex];
}

template <typename Real>
Vec4<Real> Vec4<Real>::operator + ( const Vec4<Real>& vRhs ) const {
	return Vec4<Real>( data[0] + vRhs.data[0], data[1] + vRhs.data[1], data[2] + vRhs.data[2], data[3] + vRhs.data[3] );
}

template <typename Real>
Vec4<Real> Vec4<Real>::operator - ( const Vec4<Real>& vRhs ) const {
	return Vec4<Real>( data[0] - vRhs.data[0], data[1] - vRhs.data[1], data[2] - vRhs.data[2], data[3] - vRhs.data[3] );
}

template <typename Real>
Vec4<Real> Vec4<Real>::operator * ( const Real rRhs ) const {
	return Vec4<Real>( data[0] * rRhs, data[1] * rRhs, data[2] * rRhs, data[3] * rRhs );
}

template <typename Real>
Vec4<Real> Vec4<Real>::operator / ( const Real rRhs ) const {
	return Vec4<Real>( data[0] / rRhs, data[1] / rRhs, data[2] / rRhs, data[3] / rRhs );
}

template <typename Real>
Vec4<Real> Vec4<Real>::operator - () const {
	return Vec4<Real>( -data[0], -data[1], -data[2], -data[3] );
}

template <typename Real>
Vec4<Real> Vec4<Real>::operator += ( const Vec4<Real>& vRhs ) {
	data[0] += vRhs.data[0];
	data[1] += vRhs.data[1];
	data[2] += vRhs.data[2];
	data[3] += vRhs.data[3];
}

template <typename Real>
Vec4<Real> Vec4<Real>::operator -= ( const Vec4<Real>& vRhs ) {
	data[0] -= vRhs.data[0];
	data[1] -= vRhs.data[1];
	data[2] -= vRhs.data[2];
	data[3] -= vRhs.data[3];
}

template <typename Real>
Vec4<Real> Vec4<Real>::operator *= ( const Real rRhs ) {
	data[0] *= rRhs;
	data[1] *= rRhs;
	data[2] *= rRhs;
	data[3] *= rRhs;
}

template <typename Real>
Vec4<Real> Vec4<Real>::operator /= ( const Real rRhs ) {
	data[0] /= rRhs;
	data[1] /= rRhs;
	data[2] /= rRhs;
	data[3] /= rRhs;
}

// TODO comparison operations
template <typename Real>
bool Vec4<Real>::operator == ( const Vec4<Real>& v4Rhs ) const {
	return 		this->data[0] == v4Rhs.data[0]
	       &&	this->data[1] == v4Rhs.data[1]
	       &&	this->data[2] == v4Rhs.data[2]
	       &&	this->data[3] == v4Rhs.data[3];
}

template <typename Real>
bool Vec4<Real>::operator != ( const Vec4<Real>& v4Rhs ) const {
	return 		this->data[0] != v4Rhs.data[0]
	       ||	this->data[1] != v4Rhs.data[1]
	       ||	this->data[2] != v4Rhs.data[2]
	       ||	this->data[3] != v4Rhs.data[3];
}

template <typename Real>
Real Vec4<Real>::length() const {
	return Math<Real>::Sqrt( data[0] * data[0] + data[1] * data[1] + data[2] * data[2] + data[3] * data[3] );
}

template <typename Real>
Real Vec4<Real>::squaredLength() const {
	return data[0] * data[0] + data[1] * data[1] + data[2] * data[2] + data[3] * data[3];
}

template <typename Real>
Real Vec4<Real>::normalize() {
	Real length = this->length();
	data[0] /= length;
	data[1] /= length;
	data[2] /= length;
	data[3] /= length;
	return length;
}

template <typename Real>
Real Vec4<Real>::dot( const Vec4& v4A ) const {
	return this->data[0] * v4A.data[0] + this->data[1] * v4A.data[1] + data[2] * v4A.data[2] + data[3] * v4A.data[3];
}

// Vec4 specific
template <typename Real>
Vec4<Real> Vec4<Real>::cross( const Vec4<Real>& v4V ) const {
	return Vec4<Real>( 	data[0] * v4V.data[2] - data[2] * v4V.data[0],
						data[2] * v4V.data[1] - data[1] * v4V.data[2],
						data[0] * v4V.data[1] - data[1] * v4V.data[0],
						0 ); // FIXME check this
}

template <typename Real>
Vec4<Real> Vec4<Real>::unitCross( const Vec4<Real>& v4V ) const {
	Vec4<Real> result = cross( v4V );
	result.normalize();
	return result;
}

